/**
 * Projekt do předmetu GJA - LATEX TABLE CREATOR
 *
 * Soubor: DefaultCellAttribute.java
 *
 * @author Ondřej Kubal  <xkluba00@stud.fit.vutbr.cz>
 * @author Petr Šimon    <xsimon10@stud.fit.vutbr.cz>
 */

package table;

import java.awt.*;
import javax.swing.border.*;

/**
 * Tato třída uchovávává a zpřístupňuje informace o jednotlivých buňkách naší <code>MultiSpanCellTable</code>.
 * Součást <code>AttributiveCellTableModel</code>.
 * Implementuje následující interface:
 *   CellAttribute -- přidávání/odebírání řádků/sloupců, šířky řádků/sloupců, jednotky
 *   CellSpan   -- slučování buněk
 *   ColoredCell -- barva písma/pozadí
 *   CellFont   -- písmo buňěk, zarovnání, styly
 *   CellBorder -- rámečky buněk
 */
public class DefaultCellAttribute
          implements CellAttribute , CellSpan , ColoredCell , CellFont, CellBorder
{

     protected int rowSize;
     protected int columnSize;
     protected int[][][] span;                   // CellSpan
     protected Color[][] foreground;             // ColoredCell
     protected Color[][] background;             //
     protected Font[][]  font;                   // CellFont
     protected int[][]  fontAtt;                 //
     
     protected Border[][] border;                // CellBorder - rámeček
     
     
     protected float[] widths;                   // rozměry sloupců/řádků
     protected int[] widths_m;                   //jednotky
     protected float[] heights;
     protected int[] heights_m;
     
     /**
      * Konstruktor.
      * 1x1
      */
     public DefaultCellAttribute()
     {
          this(1, 1);
     }
     
     /**
      * Konstruktor. Definovaná velikost.
      * @param numRows počet řádků
      * @param numColumns počet sloupců
      */
     public DefaultCellAttribute(int numRows, int numColumns)
     {
          setSize(new Dimension(numColumns, numRows));
     }
     
     /**
      * Inicializace hodnot.
      * Nastaví všechny buňky na nesloučené, viditelné.
      */
     protected void initValue()
     {
          for (int i = 0; i < span.length; i++)
          {
               for (int j = 0; j < span[i].length; j++)
               {
                    span[i][j][CellSpan.COLUMN] = 1;
                    span[i][j][CellSpan.ROW]    = 1;
                    //border[i][j]= new EmptyBorder(1, 2, 1, 2); //výchozí rámeček
               }
          }
     }
     
     
     //
     // CellSpan
     //
     
     /**
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return Parametry sloučení dané buňky
     */
     public int[] getSpan(int row, int column)
     {
          if (isOutOfBounds(row, column))
          {
               int[] ret_code = {1, 1};
               return ret_code;
          }
          
          return span[row][column];
     }
     
     /**
      * Nastaví parametr sloučení dané buňky.
      * ! Nedoporučuje se používat. Raději použít <code>combine</code> nebo <code>split</code>.
      * @param span
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setSpan(int[] span, int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          this.span[row][column] = span;
     }
     
     /**
      * Zjistí viditelnost buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return true pokud je viditelná, false pokud není viditelná
      */
     public boolean isVisible(int row, int column)
     {
          if (isOutOfBounds(row, column)) return false;
          
          if ((span[row][column][CellSpan.COLUMN] < 1)
                    || (span[row][column][CellSpan.ROW]    < 1)) return false;
                    
          return true;
     }
     
     
     /**
      * Zjistí, zda daná buňka je sloučená.
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return true pokud je viditelná, false pokud není viditelná
      */
     public boolean isCombined(int row, int column)
     {
          if (isOutOfBounds(row, column)) return false;
          
          if ((span[row][column][CellSpan.COLUMN] > 1)
                    || (span[row][column][CellSpan.ROW]    > 1)) return true;
                    
          return false;
     }
     
     /**
      * Provede operaci sloučení daného výběru buňek.
      * Korektně spočítá hodnoty dle popsaného schéma.
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      * @return true, pokud lze dané buňky sloučit
      */
     public boolean combine(int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return false;
          
          int    rowSpan  = rows.length;
          int columnSpan  = columns.length;
          int startRow    = rows[0];
          int startColumn = columns[0];
          
          for (int i = 0; i < rowSpan; i++)
          {
               for (int j = 0; j < columnSpan; j++)
               {
                    if ((span[startRow +i][startColumn +j][CellSpan.COLUMN] != 1)
                              || (span[startRow +i][startColumn +j][CellSpan.ROW]    != 1))
                    {
                         //System.out.println("can't combine");
                         return false;
                    }
               }
          }
          
          for (int i = 0, ii = 0; i < rowSpan; i++, ii--)
          {
               for (int j = 0, jj = 0; j < columnSpan; j++, jj--)
               {
                    span[startRow +i][startColumn +j][CellSpan.COLUMN] = jj;
                    span[startRow +i][startColumn +j][CellSpan.ROW]    = ii;
                    //System.out.println("r " +ii +"  c " +jj);
               }
          }
          
          span[startRow][startColumn][CellSpan.COLUMN] = columnSpan;
          span[startRow][startColumn][CellSpan.ROW]    =    rowSpan;
          
          return true;
     }
     
     
     /**
     * Provede operaci rozdělení sloučené buňky
     * Korektně spočítá hodnoty dle popsaného schéma.
     * @param row řádek buňky
     * @param column sloupec buňky
     */
     public void split(int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          int columnSpan = span[row][column][CellSpan.COLUMN];
          int    rowSpan = span[row][column][CellSpan.ROW];
          
          for (int i = 0; i < rowSpan; i++)
          {
               for (int j = 0; j < columnSpan; j++)
               {
                    span[row +i][column +j][CellSpan.COLUMN] = 1;
                    span[row +i][column +j][CellSpan.ROW]    = 1;
               }
          }
     }
     
     
     //
     // ColoredCell
     //
     
     /**
      * Vrátí barvu písma dané buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return barva
      */
     public Color getForeground(int row, int column)
     {
          if (isOutOfBounds(row, column)) return null;
          
          return foreground[row][column];
     }
     
     /**
      * Nastaví barvu písma dané buňky
      * @param color barva
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setForeground(Color color, int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          foreground[row][column] = color;
     }
     
     /**
     * Nastaví barvu písma vybraných buněk
     * @param color barva
     * @param rows vybrané řádky
     * @param columns vybrané sloupce
     */
     public void setForeground(Color color, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          setValues(foreground, color, rows, columns);
     }
     
     /**
      * Vrátí barvu pozadí dané buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return barva
      */
     public Color getBackground(int row, int column)
     {
          if (isOutOfBounds(row, column)) return null;
          
          return background[row][column];
     }
     
     /**
      * Nastaví barvu pozadí dané buňky
      * @param color barva
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setBackground(Color color, int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          background[row][column] = color;
     }
     
     /**
      * Nastaví barvu pozadí vybraných buněk
      * @param color barva
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     public void setBackground(Color color, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          setValues(background, color, rows, columns);
     }
     //
     
     
     //
     // CellFont
     //
     
     /**
      * Vrátí písmo dané buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return písmo buňky
      */
     public Font getFont(int row, int column)
     {
          if (isOutOfBounds(row, column)) return null;
          
          return font[row][column];
     }
     
     /**
      * Nastaví písmo dané buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setFont(Font font, int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          this.font[row][column] = font;
     }
     
     /**
      * Nastaví písmo vybraných buněk
      * @param písmo buňky
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     public void setFont(Font font, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          setValues(this.font, font, rows, columns);
     }
     
     /**
      * Vrátí atributy písma dané buňky
      * (Atributy jsou popsány výše)
      * Jze je slučovat operátorm + či or
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public int getFontAtt(int row, int column)
     {
          if (isOutOfBounds(row, column)) return CellFont.FLAG_NONE;
          
          return fontAtt[row][column];
     }
     
     /**
      * Nastaví atributy písma dané buňky
      * (Atributy jsou popsány výše)
      * Jze je slučovat operátorm + či or
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setFontAtt(int att, int row, int column)
     {
          if (isOutOfBounds(row, column)) return;
          
          fontAtt[row][column] = att;
     }
     
     /**
      * Nastaví atributy písma vybraných buněk
      * (Atributy jsou popsány výše)
      * Jze je slučovat operátorm + či or
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     public void setFontAtt(int att, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          for (int i = 0; i < rows.length; i++)
          {
               int row = rows[i];
               
               for (int j = 0; j < columns.length; j++)
               {
                    int column = columns[j];
                    fontAtt[row][column] |= att;
               }
          }
     }
     
     /**
      * Odnastaví atributy písma vybraných buněk
      * (Atributy jsou popsány výše)
      * Jze je slučovat operátorm + či or
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     public void unsetFontAtt(int att, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          for (int i = 0; i < rows.length; i++)
          {
               int row = rows[i];
               
               for (int j = 0; j < columns.length; j++)
               {
                    int column = columns[j];
                    fontAtt[row][column] &= ~att;
               }
          }
     }
     //
     
     //
     // CellBorder //Přidáno
     //
     
     /**
      * Nastaví rámeček dané buňky
       * @param border rámeček
      * @param row řádek buňky
      * @param column sloupec buňky
      */
     public void setBorder(Border border, int row, int col)
     {
          if (isOutOfBounds(row, col)) return;
          
          this.border[row][col] = border;
     }
     
     /**
     * Vrátí rámeček dané buňky
      * @param row řádek buňky
      * @param column sloupec buňky
      * @return rámeček
     */
     public Border getBorder(int row, int col)
     {
          if (isOutOfBounds(row, col)) return null;
          
          return border[row][col];
     }
     
     /**
      * Nastaví rámeček vybraných buněk -vyplní celou oblast stejným rámečkem
      * @param border rámeček
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     public void setBorder(Border border, int[] rows, int[] columns)
     {
          if (isOutOfBounds(rows, columns)) return;
          
          setValues(this.border, border, rows, columns);
     }
     //
     
     
     /**
      * Nastaví šířku sloupce
      * @param col sloupec
      * @param width šířka (velikost)
      * @param type jednotky šířky
      */
     public void setWidth(int col, float width, int type)
     {
          if (isOutOfBounds(0, col)) return;
          
          this.widths[col] = width;
          this.widths_m[col] = type;
     }
     
     /**
     * Nastaví výšku řádeku
     * @param row řádek
     * @param width výška (velikost)
     * @param type jednotky výšky
     */
     public void setHeight(int row, float width, int type)
     {
          if (isOutOfBounds(row, 0)) return;
          
          this.heights[row] = width;
          this.heights_m[row] = type;
     }
     
     /**
      * Vrátí šířku sloupce
      * @param col sloupec
      * @return šířka sloupce (velikost)
      */
     public float getWidth(int col)
     {
          if (isOutOfBounds(0, col)) return 0;
          
          return this.widths[col];
     }
     
     /**
      * Vrátí výšku řádku
      * @param row řádek buňky
      * @return výška řádku (velikost)
      */
     public float getHeight(int row)
     {
          if (isOutOfBounds(row, 0)) return 0;
          
          return this.heights[row];
     }
     
     /**
      * Vrátí jednotky pro šířku sloupce
      * @param col sloupec
      * @return šířka sloupce - jednotky
      */
     public int getWidthType(int col)
     {
          if (isOutOfBounds(0, col)) return SIZE_NONE;
          
          return this.widths_m[col];
     }
     
     /**
      * Vrátí jednotky pro výšku řádku
      * @param row řádek buňky
      * @return výška řádku - jednotky
      */
     public int getHeightType(int row)
     {
          if (isOutOfBounds(row, 0)) return SIZE_NONE;
          
          return this.heights_m[row];
     }
     
     
     //
     // CellAttribute //upraveno
     //
     
     /**
      * Odstraní sloupec z modelu
      * @param index číslo sloupce
      */
     public boolean removeColumn(int index)
     {
          int numRows    = span.length;
          int numColumns = span[0].length;
          
          if (index >= numColumns) return false; //hlídání rozsahu
          
          //ověření zda sloupec neobsahuje sloučené buňky
          for (int i = 0; i < numRows; i++)
          {
               if ((span[i][index][CellSpan.COLUMN] != 1)
                         || (span[i][index][CellSpan.ROW]    != 1))
               {
                    //System.out.println("can't combine");
                    return false; //nemůžeme ho odstranit !!!! došlo by k rozložení dat
               }
          }
          
          //záloha
          int[][][] oldSpan = span;
          Color[][] oldForeground = foreground;
          Color[][] oldBackground = background;
          Font[][]  oldFont = font;
          int[][]   oldFontAtt = fontAtt;
          Border[][] oldBorder = border;
          float[] oldWidths = widths;                   // rozměry sloupců/řádků
          int[] oldWidths_m = widths_m;                   //jednotky
          
          //zvětšní polí
          span       = new    int[numRows][numColumns - 1][2];
          foreground = new  Color[numRows][numColumns - 1];
          background = new  Color[numRows][numColumns - 1];
          font       = new   Font[numRows][numColumns - 1];
          fontAtt    = new    int[numRows][numColumns - 1];
          border     = new Border[numRows][numColumns - 1];
          
          widths = new float[numColumns - 1];
          widths_m = new int[numColumns - 1];
          
          for (int j = 0; j < index; j++)
          {
               widths[j] = oldWidths[j];
               widths_m[j] = oldWidths_m[j];
          }
          
          for (int j = index + 1; j < numColumns; j++)
          {
               widths[j-1] = oldWidths[j];
               widths_m[j-1] = oldWidths_m[j];
          }
          
          //překopírování obsahu
          for (int i = 0; i < numRows; i++)
          {
               //před vynechaným sloupcem
               for (int j = 0; j < index; j++)
               {
                    span[i][j][CellSpan.COLUMN] = oldSpan[i][j][CellSpan.COLUMN];
                    span[i][j][CellSpan.ROW]    = oldSpan[i][j][CellSpan.ROW];
                    foreground[i][j] = oldForeground[i][j];
                    background[i][j] = oldBackground[i][j];
                    font[i][j] = oldFont[i][j];
                    fontAtt[i][j] = oldFontAtt[i][j];
                    border[i][j] = oldBorder[i][j];
               }
               
               //za vynechaným sloupcem
               for (int j = index + 1; j < numColumns; j++)
               {
                    span[i][j-1][CellSpan.COLUMN] = oldSpan[i][j][CellSpan.COLUMN];
                    span[i][j-1][CellSpan.ROW]    = oldSpan[i][j][CellSpan.ROW];
                    foreground[i][j-1] = oldForeground[i][j];
                    background[i][j-1] = oldBackground[i][j];
                    font[i][j-1] = oldFont[i][j];
                    fontAtt[i][j-1] = oldFontAtt[i][j];
                    border[i][j-1] = oldBorder[i][j];
               }
          }
          
          columnSize--;
          return true;
     }
     
     /**
      * přidá sloupec atributů do modelu
      * @param row řádek
      */
     public void addColumn()
     {
          int numRows    = span.length;
          int numColumns = span[0].length;
          
          //záloha
          int[][][] oldSpan = span;
          Color[][] oldForeground = foreground;
          Color[][] oldBackground = background;
          Font[][]  oldFont = font;
          int[][]   oldFontAtt = fontAtt;
          Border[][] oldBorder = border;
          float[] oldWidths = widths;                   // rozměry sloupců/řádků
          int[] oldWidths_m = widths_m;                   //jednotky
          
          //zvětšní polí
          span       = new    int[numRows][numColumns + 1][2];
          foreground = new  Color[numRows][numColumns + 1];
          background = new  Color[numRows][numColumns + 1];
          font       = new   Font[numRows][numColumns + 1];
          fontAtt    = new    int[numRows][numColumns + 1];
          border     = new Border[numRows][numColumns + 1];
          
          widths = new float[numColumns + 1];
          widths_m = new int[numColumns + 1];
          
          for (int j = 0; j < numColumns; j++)
          {
               widths[j] = oldWidths[j];
               widths_m[j] = oldWidths_m[j];
          }
          
          widths[numColumns] = 0;
          widths_m[numColumns] = 0;
          
          //překopírování obsahu
          for (int i = 0; i < numRows; i++)
               for (int j = 0; j < numColumns; j++)
               {
                    span[i][j][CellSpan.COLUMN] = oldSpan[i][j][CellSpan.COLUMN];
                    span[i][j][CellSpan.ROW]    = oldSpan[i][j][CellSpan.ROW];
                    foreground[i][j] = oldForeground[i][j];
                    background[i][j] = oldBackground[i][j];
                    font[i][j] = oldFont[i][j];
                    fontAtt[i][j] = oldFontAtt[i][j];
                    border[i][j] = oldBorder[i][j];
               }
               
          //přidání nového sloupce
          for (int i = 0; i < numRows; i++)
          {
               span[i][numColumns][CellSpan.COLUMN] = 1;
               span[i][numColumns][CellSpan.ROW]    = 1;
               fontAtt[i][numColumns] = 0;
          }
          
          columnSize++;
     }
     
     /**
      * Vloží řádek do modelu
      * @param row řádek
      */
     public void addRow()
     {
          int numRows    = span.length;
          int numColumns = span[0].length;
          
          //záloha
          int[][][] oldSpan = span;
          Color[][] oldForeground = foreground;
          Color[][] oldBackground = background;
          Font[][]  oldFont = font;
          int[][]  oldFontAtt = fontAtt;
          Border[][] oldBorder = border;
          
          float[] oldHeights = heights;
          int[] oldHeights_m = heights_m;
          
          //zvětšní polí
          span       = new    int[numRows+1][numColumns][2];
          foreground = new  Color[numRows+1][numColumns];
          background = new  Color[numRows+1][numColumns];
          font       = new   Font[numRows+1][numColumns];
          fontAtt    = new    int[numRows+1][numColumns];
          border     = new Border[numRows+1][numColumns];
          heights   = new float[numRows+1];
          heights_m = new int[numRows+1];
          
          //kopie atributů
          System.arraycopy(oldSpan, 0, span, 0, numRows);
          System.arraycopy(oldForeground, 0, foreground, 0, numRows);
          System.arraycopy(oldBackground, 0, background, 0, numRows);
          System.arraycopy(oldFont, 0, font, 0, numRows);
          System.arraycopy(oldFontAtt, 0, fontAtt, 0, numRows);
          System.arraycopy(oldBorder, 0, border, 0, numRows);
          
          System.arraycopy(oldHeights, 0, heights, 0, numRows);
          System.arraycopy(oldHeights_m, 0, heights_m, 0, numRows);
          
          heights[numRows] = 0;
          heights_m[numRows] = 0;
          
          //přidání nového řádku
          for (int i = 0; i < numColumns; i++)
          {
               span[numRows][i][CellSpan.COLUMN] = 1;
               span[numRows][i][CellSpan.ROW]    = 1;
               fontAtt[numRows][i] = 0;
          }
          
          rowSize++;
     }
     
     /**
      * Odstraní řádek z modelu
      * @param index číslo řádku
      */
     public boolean removeRow(int index)
     {
          int numRows    = span.length;
          int numColumns = span[0].length;
          
          //ověření zda sloupec neobsahuje sloučené buňky
          for (int i = 0; i < numColumns; i++)
          {
               if ((span[index][i][CellSpan.COLUMN] != 1)
                         || (span[index][i][CellSpan.ROW]    != 1))
               {
                    //System.out.println("can't combine");
                    return false; //nemůžeme ho odstranit !!!! došlo by k rozložení dat
               }
          }
          
          //záloha
          int[][][] oldSpan = span;
          Color[][] oldForeground = foreground;
          Color[][] oldBackground = background;
          Font[][]  oldFont = font;
          int[][]  oldFontAtt = fontAtt;
          Border[][] oldBorder = border;
          
          float[] oldHeights = heights;
          int[] oldHeights_m = heights_m;
          
          //zvětšní polí
          span       = new    int[numRows-1][numColumns][2];
          foreground = new  Color[numRows-1][numColumns];
          background = new  Color[numRows-1][numColumns];
          font       = new   Font[numRows-1][numColumns];
          fontAtt    = new    int[numRows-1][numColumns];
          border     = new Border[numRows-1][numColumns];
          
          heights   = new float[numRows-1];
          heights_m = new   int[numRows-1];
          
          //kopie atributů
          System.arraycopy(oldSpan, 0, span, 0, index);
          System.arraycopy(oldForeground, 0, foreground, 0, index);
          System.arraycopy(oldBackground, 0, background, 0, index);
          System.arraycopy(oldFont, 0, font, 0, index);
          System.arraycopy(oldFontAtt, 0, fontAtt, 0, index);
          System.arraycopy(oldBorder, 0, border, 0, index);
          
          System.arraycopy(oldHeights, 0, heights, 0, index);
          System.arraycopy(oldHeights_m, 0, heights_m, 0, index);
          //překopírování obsahu
          //za vynechaným sloupcem
          
          
          for (int i = index + 1; i < numRows; i++)
          {
               heights[i-1] = oldHeights[i];
               heights_m[i-1] = oldHeights_m[i];
               
               for (int j = 0; j < numColumns; j++)
               {
                    span[i-1][j][CellSpan.COLUMN] = oldSpan[i][j][CellSpan.COLUMN];
                    span[i-1][j][CellSpan.ROW]    = oldSpan[i][j][CellSpan.ROW];
                    foreground[i-1][j] = oldForeground[i][j];
                    background[i-1][j] = oldBackground[i][j];
                    font[i-1][j] = oldFont[i][j];
                    fontAtt[i-1][j] = oldFontAtt[i][j];
                    border[i-1][j] = oldBorder[i][j];
               }
          }
          
          rowSize--;
          return true;
     }
     
     //NUTNO UPRAVIT !!!!!!!!
     public void insertRow(int row)
     {
          /*    int[][][] oldSpan = span;
              int numRows    = oldSpan.length;
              int numColumns = oldSpan[0].length;
              span = new int[numRows + 1][numColumns][2];
              if (0 < row) {
                System.arraycopy(oldSpan,0,span,0,row-1);
              }
              System.arraycopy(oldSpan,0,span,row,numRows - row);
              for (int i=0;i<numColumns;i++) {
                span[row][i][CellSpan.COLUMN] = 1;
                span[row][i][CellSpan.ROW]    = 1;
              }*/
     }
     
     /**
      * Zjistí počet řádků a sloupců
      * @return rozměry
      */
     public Dimension getSize()
     {
          return new Dimension(rowSize, columnSize);
     }
     
     /**
      * Nastaví počet řádků a sloupců
      * !! Nuluje data !!
      * @param size rozměry
      */
     public void setSize(Dimension size)
     {
          columnSize = size.width;
          rowSize    = size.height;
          span = new int[rowSize][columnSize][2];   // 2: COLUMN,ROW
          foreground = new Color[rowSize][columnSize];
          background = new Color[rowSize][columnSize];
          font = new Font[rowSize][columnSize];
          fontAtt = new int[rowSize][columnSize];
          border =  new Border[rowSize][columnSize]; //nastavíme velikost vnitřního pole
          
          widths = new float[columnSize];
          widths_m = new int[columnSize];
          heights = new float[rowSize];
          heights_m = new int[rowSize];
          
          initValue();
     }
     
     /*
     public void changeAttribute(int row, int column, Object command) {
     }
     
     public void changeAttribute(int[] rows, int[] columns, Object command) {
     }
     */
     
     /**
      * Zkonroluje, zda je daná buňka přístupná.
      * @param row číslo řádku
      * @param column číslo sloupce
      * @return true pokud se nachází mimo přístupnou oblast, jinak false
      */
     protected boolean isOutOfBounds(int row, int column)
     {
          if ((row    < 0) || (rowSize    <= row) || (column < 0) || (columnSize <= column))
          {
               return true;
          }
          
          return false;
     }
     
     /**
      * Zkonroluje, zda jsou dané buňky přístupné.
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      * @return true pokud se nachází mimo přístupnou oblast, jinak false
      */
     protected boolean isOutOfBounds(int[] rows, int[] columns)
     {
          for (int i = 0; i < rows.length; i++)
          {
               if ((rows[i] < 0) || (rowSize <= rows[i])) return true;
          }
          
          for (int i = 0; i < columns.length; i++)
          {
               if ((columns[i] < 0) || (columnSize <= columns[i])) return true;
          }
          
          return false;
     }
     
     
     /**
      * Univerzání nastavovač hodnot v libovolném dvourozměrném poli.
      * @param target cílové pole
      * @param value vkládaný objekt
      * @param rows vybrané řádky
      * @param columns vybrané sloupce
      */
     protected void setValues(Object[][] target, Object value,
                              int[] rows, int[] columns)
     {
          for (int i = 0; i < rows.length; i++)
          {
               int row = rows[i];
               
               for (int j = 0; j < columns.length; j++)
               {
                    int column = columns[j];
                    target[row][column] = value;
               }
          }
     }




     /**
      * Vrati rtezec s jednotkou, ktery odpovida zadanemu parametru
      * @param type jednotka
      * @return retezec odpoviajici ciselne konstante jednotky
      */
     public String getTypeString(int type)
     {
        switch (type)
        {
            case SIZE_CM:
                return "cm";
            case SIZE_PIX:
                return "px";
            case SIZE_MM:
                return "mm";
            case SIZE_IN:
                return "in";
            case SIZE_PT:
                return "pt";
            case SIZE_PC:
                return "pc";
            case SIZE_EM:
                return "em";
            default:
                return "";
        }
     }
}
